package de.recipeminer.persistence;

import com.google.common.collect.Maps;
import org.apache.log4j.Logger;

import java.io.File;
import java.util.Map;

/**
 * A registry for opened embedded Db4o database files. This is useful in cases,
 * when several Db4oDescriptors actually reference the same database file. It
 * also allows to close all opened databases from a central place in case of
 * an unrecoverable error.
 *
 * @author Markus Ackermann
 */
public class Db4oContainers {
    private static Logger logger = Logger.getLogger(Db4oContainers.class);
    private static Db4oContainers instance = new Db4oContainers();
    private static Db4oDescriptor defaultDatabase = Db4oDescriptor.DEFAULT;
    private Map<File, Db4oContainer> openedFiles = Maps.newHashMap();
    
    public static Db4oContainers getInstance() {
        return instance;
    }

    public static Db4oContainer get(Db4oDescriptor desc) {
        return getInstance().getContainer(desc);
    }

    public static Db4oContainer getDefault() {
        return getInstance().getContainer(defaultDatabase);
    }

    public static void release(Db4oDescriptor desc) {
        getInstance().releaseContainer(desc.getDbFile());
    }

    public Db4oContainer getContainer(Db4oDescriptor desc) {
        Db4oContainer ret = openedFiles.get(desc.getDbFile());
        if(ret != null) {
            ret.open();            
            return ret;
        } else {
            ret = new Db4oContainer(desc.getConfigurationProvider(), desc.getDbFile());
            ret.open();
            openedFiles.put(desc.getDbFile(),ret);
            return ret;
        }
    }

    public void releaseContainer(Db4oContainer container) {
        releaseContainer(container.getDataBaseFile());
    }
    
    void releaseContainer(File dbfile) {
        if(openedFiles.containsKey(dbfile)) {
            Db4oContainer container = openedFiles.get(dbfile);
            container.closeAllSessions();
            openedFiles.remove(container.getDataBaseFile());
        }
    }

    public void rollbackAndreleaseAll() {
        while(! openedFiles.isEmpty()) {
            // new iterator has to be created every time to circumvent ConcurrentModificationException
            Db4oContainer container = openedFiles.values().iterator().next();
            container.rollback();
            releaseContainer(container);
        }
    }

    public static Db4oDescriptor getDefaultDatabase() {
        return defaultDatabase;
    }

    public static void setDefaultDatabase(Db4oDescriptor defaultDatabase) {
        Db4oContainers.defaultDatabase = defaultDatabase;
    }
}
